Files of this type and auxiliary type contain documents for Medley(TM).
Medley is a WYSIWYG application that integrates word processing, paint, and page layout programs, with the addition of a spelling checker and thesaurus. The page layout function supports various shapes for art and text areas. Text automatically wraps around or within these areas, including irregularly shaped regions. The word processor is full-featured, as is the paint program. The dictionary has 80,000 words.
For more information on Medley, contact:
Milliken Publishing Company
1100 Research Blvd.
St. Louis, MO 63132
Attention: Medley Technical Support
(314) 991-4220
The Medley file format is copyrighted (C) 1988 by Milliken Publishing Company and is printed here with permission.
The following definition is used in this document in addition to those defined for all Apple II file types:
Medley files are basically standard, single-linked tree structures. There is a single object at the top of the tree, and other objects may branch off this parent object. Each child object is linked to the parent by a pointer to the child contained within the parent object. A non-standard thing about the Medley tree structure is that some objects may have regions or polygons associated with them. The handles to these objects are stored in the parent object when in memory, but on disk these handles are quite meaningless. Because of this difference, the regions or polygons are simply appended to the parent object itself when written to disk. The size of the region or polygon is added to the size of the parent object, giving an aggregate size for the complex object on disk.
The file is written to disk in an order based on a simple tree-walking algorithm. This algorithm starts with the highest parent object and writes it to disk. The parent object is checked for child objects. If one exists, it is written to disk, and then it is checked for child objects. This tree-walking continues until an object runs out of children. When that occurs, Medley backs up one tree level, writes the next child object to disk, and scans it for children. This method continues until all objects are written to disk.
For example, if a parent object named A had two child objects named B and C, where B had children E and F, and C had children G and H, the objects would be written to disk in the following order: A, B, D, E, C, F, G. Figure 1 illustrates this structure.
_________
| |
| A |
|_________|
|---------------|---------------|
____|____ ____|____
| | | |
| B | | C |
|_________| |_________|
|-------|-------|---------------|-------|-------|
____|____ ____|____ ____|____ ____|____
| | | | | | | |
| D | | E | | F | | G |
|_________| |_________| |_________| |_________|
Figure 1 - Example of Parent and Child Tree Structure
Some Medley objects, when in memory, have handles to other objects (such as regions or polygons) in them. Since handles are meaningless on disk, Medley stores these complex objects in an aggregate form by writing the contents of each associated handle to disk following the regular object.
All objects have a common 13-byte header, which is as follows:
Each object has the header listed above followed by object-specific data. For this reason, the description of each object will start with offset +013 (the byte following the header).
Note: The following three fields are in Medley 2.0 files, but do not exist in Medley 1.0 files. If you are reading a 1.0 file, the value of revNum will be $0000. If reading a 1.0 File Object, resize it to 2.0 size (including the three fields below) and initialize their values to the values given below.
workHeight := topMrgn + bottomMrgn if [condensed is non-zero] then workHeight := workHeight * 2 workHeight := pageHeight - workHeight workHeight := workHeight * [pixels per vertical inch] workHeight := workHeight + $0000FFFF [this counts a fractional point as a whole point] i := HiWord(workHeight) [this gives the integer portion] i := i + 3 [accounts for 3-pixel page breaks] i := (16384 - 208) / i [gives number of pages in conceptual drawing space. Since Medley allows 48-point characters plus leading, the tallest a text rectangle may be is 208 pixels. Text that does not fit in maxNumPages is kept around in a non- displayable, non-editable, non-printable page. Any shortening of the document will cause some or all of the previously non- displayed text to flow up into the document.] i := min(32,i) [32 is the absolute maximum number of pages Medley allows due to QuickDraw's conceptual drawing space limitations.] maxNumPages := i
Pages are the first-level children of files. There is one page object for each page in a document (file object).
Paragraphs are the children of the file object; they are not the children of page objects since a paragraph may be seen on more than one page or page part. Paragraph objects are, however, stored on disk immediately following page objects and their children. Paragraph objects are first-level objects also.
MiniRects have the following format:
A Ruler in the document will be after the miniRects, if there are any. The offset to the Ruler is given by rulerOffset. Rulers are formatted as follows:
Tabs are formatted as follows:
Following miniRects and rulers is the actual character data for this paragraph. This is all Bytes. However, a Byte value of $01 through $07 indicates the beginning of a Font Escape. Font Escapes indicate changes in style or size of the text, and are formatted as follows:
The text portion of a paragraph always begins with a Font Escape and ends with the end-of-paragraph character Byte $A6. This makes the minimum size of a paragraph (assuming no miniRects or rulers) thirty-eight bytes (32 bytes for the Paragraph Object, five bytes for the Font Escape and one byte for the $A6).
Area Objects are the children of pages or paragraphs.
At this point is the description of the area itself. This description varies on the type field above:
For rectangles (type = 2):
For round rectangle (type = 3):
For ovals (type = 4):
For Polygons (type = 5):
These objects are the last items in the area object.
Art Objects are the children of pages, paragraphs or areas.
The Document Dictionary Object is the very last child of the file object, and contains all the words the spelling checker should ignore even though they are not in the main dictionary.
The format of word entries is as follows:
The length of a record is the length of string plus three bytes (one for recordLength, one for replaceFlag, and a zero termination byte).
When reading a Medley file, objects with regions or polygons will have to be treated specially, since the handles in the objects are invalid and the regions or polygons actually follow the object in the disk file.
A sequence for reconstructing Medley files in memory is as follows:
Note: By zeroing the handles before reading the objects, you can return from this function with an error, and the calling routine will be able to dispose of all handles that were actually created. The calling routine will know if a handle was actually created or not by examining the handle field in the object; NIL handles were not created.
The entire file does not have to be read from disk. By using the size field, you can skip to the next object in the file. Using this technique, you can scan the file for whatever it is that interests you.
Note: You may have noticed that objects successfully created in memory will have a table of handles to children at the end. Objects on disk will not have these handles, since the handles on disk are meaningless. The child handle table is reconstructed as the file is loaded into memory.
The file object is the first you will encounter in a Medley file. Its children are ordered as follows:
Other objects are optional, but will appear in the following order:
Medley was written mostly in C. Below are some structures relevant to C programs reading Medley files. Descriptions of the fields may be found earlier in this Note.
#define NULLOBJ 0 /* Object type assignments. */
#define ROOTOBJ 1 /* These are used in the deskObj 'types' field. */
#define FILEOBJ 2
#define PAGEOBJ 3
#define PGPHOBJ 4
#define AREAOBJ 5
#define ARTOBJ 6
#define DOCDICTOBJ 10
#define AREANULL 0 /* Area object sub-type assignments. */
#define AREAGROUP 1 /* These are used in the areaObj 'types' field. */
#define AREARECT 2
#define AREARRECT 3
#define AREAOVAL 4
#define AREAPOLY 5
#define medleyMainType 0x54
#define medleyAuxType 0xDD3E
#define medleyInfo 1
#define auxDictType 2
#define ARTCONTENT 0 /* These are used in the 'contentType' field of
area objects.*/
#define WWDOWN 1
#define WWACROSS 2
#define LWGRAYSCALE 0x0001
#define SAMEESC 0 /* These are used in paragraph objects. */
#define FONTESC 1
#define SUPERESC 2
#define SUBESC 3
#define ESCAPES 7
#define SIZEFONTESC 5 /* More paragraph equates. */
#define ENDPGPHCHR 0xA6
#define TABCHR 9
#define SOFTHYPHEN 30
#define STICKYSPACE 31
#define PAGEBREAK 0x80 /* These are used in the pgphObj 'flags' field. */
#define LEFTJUST 0x00
#define RIGHTJUST 0x01
#define CENTERJUST 0x02
#define FULLJUST 0x03
#define JUSTTYPES 0x03
#define LEFTTAB 0x00 /* These are used in the ruler field of paragraph
objects. */
#define RIGHTTAB 0x01
#define CENTERTAB 0x02
#define DECIMALTAB 0x03
#define TABTYPES 0x03
#define NOLEADER 0x00
#define DOTSLEADER 0x01
#define DASHESLEADER 0x02
#define SOLIDLEADER 0x03
typedef struct Ruler {
unsigned char leftPgphMrgn;
unsigned char rightPgphMrgn;
unsigned char pgphIndent;
unsigned char numTabs;
unsigned int tab[];
} Ruler;
#define NEWREVNUM 0x0100
typedef union URect {
Rect rect;
struct {
long p1;
long p2;
} point;
struct {
Point p1;
Point p2;
} ele;
} URect;
typedef union UPoint {
Point ele;
long point;
} UPoint;
typedef struct region {
unsigned int size;
union URect BBox;
int data[];
} region;
typedef struct polygon {
int size;
union URect BBox;
union UPoint point[];
} polygon;
typedef union ourFontID {
unsigned long fid;
struct {
unsigned int famNum;
char fontStyle;
char fontSize;
} f;
} ourFontID;
struct deskObj {
char type; $00
unsigned int numChildren; $01
unsigned long endData; $03
unsigned long reserved; $07
unsigned int objRefNum; $0B
$0D
union d {
data[]; /* Plain label object access field. */
struct file { /* Level 1 objects are files. */
union URect rect; /* $0D */
char pathName[129]; /* $15 */
char saved; /* $96 */
GrafPortPtr windowPtr; /* $97 */
char windowNameIndx; /* $9B */
long windowOrigin; /* $9C */
long windowSize; /* $A0 */
long COrigin; /* $A4 */
struct deskObj **editHndl; /* $A8 */
unsigned int editOffset; /* $AC */
union URect cursor; /* $AE */
char showAllBorders; /* $B6 */
union URect updateRect; /* $B7 */
unsigned long topMrgn; /* $BF */
unsigned long bottomMrgn; /* $C3 */
unsigned long leftMrgn; /* $C7 */
unsigned long rightMrgn; /* $CB */
unsigned long gutterMrgn; /* $CF */
unsigned long pageWidth; /* $D3 */
unsigned long pageHeight; /* $D7 */
int selectPage; /* $DB */
int numSelected; /* $DD */
int sizingDot; /* $DF */
int effectivePage; /* $E1 */
PrRec printRecord; /* $E3 */
int interruptMode; /* $16F */
char editScroll; /* $171 */
struct deskObj **firstHndl; /* $172 */
int firstMrn; /* $176 */
unsigned int selectMode; /* $178 */
char showPgphMarks; /* $17A */
char showSpaces; /* $17B */
char showMoveChangeInfo; /* $17C */
union URect moveChangeInfoRect; /* $17D */
char addNewUndo; /* $185 */
unsigned int revNum; /* $186 */
char showRulers; /* $188 */
unsigned int windowType; /* $189 */
char auxDictPathname[129]; /* $18B */
unsigned int grayScale; /* $20C */
unsigned int printRecordDefined; /* $20E */
char evenPageNumText[48]; /* $210 */
char oddPageNumText[48]; /* $240 */
unsigned int pageNumInfo[MAXNUMPAGES];/* $270 */
unsigned int affectPageRange; /* $2B0 */
ourFontID pageNumFont; /* $2B2 */
unsigned int startPageNum; /* $2B6 */
unsigned int offsetFromEdge; /* $2B8 */
unsigned int maxNumPages; /* $2BA */
unsigned int condensed; /* $2BC */
char reserved[6]; /* $2BE */
} file; /* $2C4 */
struct page {
union URect rect; /* $0D */
char wrapDir; /* $15 */
region **rgn; /* $16 */
char hideGlobalArt; /* $1A */
char hideGlobalPageParts; /* $1B */
} page; /* $1C */
struct pgph { /* Must be level 2 or greater. */
unsigned int wrapHere; /* $0D */
unsigned int fullWrap; /* $0F */
unsigned int rulerOffset; /* $11 */
unsigned int dataOffset; /* $13 */
unsigned int numRects; /* $15 */
unsigned int begInvOffset; /* $17 */
unsigned int endInvOffset; /* $19 */
char topLeading; /* $1B */
char botLeading; /* $1C */
char begPgphGap; /* $1D */
char endPgphGap; /* $1E */
char flags; /* $1F */
struct miniRect { /* $20 */
union URect rect;
unsigned int begOffset;
unsigned int endOffset;
} miniRect[];
/* Ruler goes here if there is a custom ruler for this paragraph.*/
/* Text starts after the ruler. Text always
starts with a fontEsc. A fontEsc is 5 bytes,
a typeByte followed by the fontID. Text
always ends with end-of-pgph chr. */
} pgph; /* $20 */
struct area {
char type; /* $0D */
char select; /* $0E */
char showBorder; /* $0F */
char contentType; /* $10 */
region **rgn; /* $11 */
region **interiorRgn; /* $15 */
region **sizingRgn; /* $19 */
unsigned int flags; /* $1D */
unsigned int reserved; /* $1F */
union obj {
union URect rect; /* $21 */
struct rrect {
union URect rect; /* $21 */
int height; /* $29 */
int width; /* $2B */
} rrect;
union URect oval; /* $21 */
polygon **poly; /* $21 */
} obj;
} area; /* $2D */
struct art {
union URect BBox; /* $0D */
union UPoint offsetFromRgn; /* $15 */
char artImage[]; /* $19 */
} art;
struct docDict {
unsigned int count; /* $0D */
char wordList[] /* $0F */
} docDict; /* $0F */
} d;
};
This and all of the other Apple II Technical Notes have been converted to HTML by Aaron Heiss as a public service to the Apple II community, with permission by Apple Computer, Inc. Any and all trademarks, registered and otherwise, are properties of their owners.